package org.jsbd.boss.service.impl;

import java.text.SimpleDateFormat;
import java.util.*;

import javax.annotation.Resource;

import org.apache.commons.lang.time.DateFormatUtils;
import org.jsbd.boss.common.ConstantsCmp;
import org.jsbd.boss.common.redis.RedisClient;
import org.jsbd.boss.dao.*;
import org.jsbd.boss.domian.ChannelApkConfigBaseModel;
import org.jsbd.boss.domian.ChannelApkConfigTimeModel;
import org.jsbd.boss.domian.ChannelApkInfo;
import org.jsbd.boss.domian.channel.ApkRetentConfig;
import org.jsbd.boss.domian.channel.BrushConfig;
import org.jsbd.boss.domian.channel.ChannelApkConfig;
import org.jsbd.boss.domian.channel.TimeBaseModel;
import org.jsbd.boss.service.IChannelLimitService;
import org.jsbd.boss.service.ITimeModelTempleteService;
import org.jsbd.boss.util.CacheKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 渠道任务配置
 *
 * @author <a href="mailto:zhangbinghua@zhexinit.com" >zbh</a>
 * @version 1.0.0
 */
@Service
public class ChannelLimitService implements IChannelLimitService {
    public static final Logger LOGGER = LoggerFactory.getLogger(ChannelLimitService.class);

    @Autowired
    private IChannelApkInfoDAO channelApkInfoDAO;

    @Autowired
    private IChannelApkLimitDAO channelApkLimitDAO;

    @Autowired
    private IChannelApkBaseLimitDAO channelApkBaseLimitDAO;
    @Autowired
    private IDmChannelRetentDAO dmChannelRetentDAO;

    @Resource
    private IChannelApkConfigDAO channelApkConfigDAO;

    @Autowired
    private RedisClient redisClient;

    private static final int ONE_DAY = 60 * 60 * 24;

    @Resource
    private ITimeModelTempleteService timeModelTempleteService;

    @Resource
    private IBrushConfigDao brushConfigDao;

    @Override
    public List<ChannelApkConfigBaseModel> selectChannelApkConfigModel(ChannelApkConfigBaseModel configModel) {
        return channelApkBaseLimitDAO.selectChannelApkConfigModel(configModel);
    }

    @Override
    public boolean checkLimit(String mark) {
        int successNum = getSuccessNumBymark(mark);
        int limitNum = getCurrentLimitNumBymark(mark);
        if (successNum < limitNum) {
            LOGGER.info("mark[{}] checkLimit true,successNum[{}],limitNum[{}]", new Object[]{mark, successNum, limitNum});
            return true;
        }
        LOGGER.info("mark[{}] checkLimit false,successNum[{}],limitNum[{}]", new Object[]{mark, successNum, limitNum});
        return false;
    }

    /**
     * 获取当前mark的 成功数
     *
     * @param mark
     * @return
     * @author <a href="mailto:zhangbinghua@zhexinit.com" >zbh</a>
     */
    private int getSuccessNumBymark(String mark) {
        long ttl = redisClient.getTtl(CacheKey.CHANNEL_MARK_SUCCESS_KEY + mark);
        // 超过5分钟，重新查一下成功数
        if (ttl < 0 || ttl > CacheKey.MEMCACHE_EXPIRY_TIME) {
            int successNum = dmChannelRetentDAO.selectSuccessMark(mark);
            redisClient.SetLong(CacheKey.CHANNEL_MARK_SUCCESS_KEY + mark, new Long(successNum), CacheKey.MEMCACHE_EXPIRY_TIME);
        }
        return redisClient.getLong(CacheKey.CHANNEL_MARK_SUCCESS_KEY + mark).intValue();
    }

    /**
     * getCurrentLimitNumBymark:获取当前mark的当前时间的限制数量
     *
     * @param mark
     * @return
     * @author <a href="mailto:zhangbinghua@zhexinit.com" >zbh</a>
     */
    private int getCurrentLimitNumBymark(String mark) {
        ChannelApkConfigTimeModel timeModel = getCurrentLimitModelBymark(mark);
        return timeModel.getSpDayLimit();
    }

    @Override
    public ChannelApkConfigTimeModel getCurrentLimitModelBymark(String mark) {
        // 如果有配置分时间则去当前时间的现在数量，如果没有配置分时间则取总数
        String current = getCurrentIntervalTime();
        ChannelApkInfo channelapkinfo = channelApkInfoDAO.getConfigByMark(mark);
        int daylimit = channelapkinfo.getDaylimit();
        // 判断是否配置了日限，无日限则不控制
        if (daylimit <= 0) {
            return null;
        }
        Map<String, ChannelApkConfigTimeModel> timeModelMap = getTimeModelByMark(mark, daylimit);
        // 如果没有mark的模型，证明没有配置日限
        if (timeModelMap == null) {
            LOGGER.info("mark没有取到日限模型，mark[{}]", mark);
            return null;
        }
        ChannelApkConfigTimeModel timeModel = timeModelMap.get(current);
        return timeModel;
    }

    @Override
    public ChannelApkConfigTimeModel getCurrentRetentLimitModelBymark(String mark) {
        // 如果有配置分时间则去当前时间的现在数量，如果没有配置分时间则取总数
        String current = getCurrentIntervalTime();
        Map<String, ChannelApkConfigTimeModel> timeModelMap = getTimeRetentModelByMark(mark);
        // 如果没有mark的模型，证明没有配置日限
        if (timeModelMap == null) {
            LOGGER.info("mark没有取到日限模型，mark[{}]", mark);
            return null;
        }
        ChannelApkConfigTimeModel timeModel = timeModelMap.get(current);
        return timeModel;
    }

    /**
     * getTimeModelByMark:获取当前mark的日限模型
     *
     * @param mark
     * @return
     * @author <a href="mailto:zhangbinghua@zhexinit.com" >zbh</a>
     */
    @Override
    public Map<String, ChannelApkConfigTimeModel> getTimeModelByMark(String mark, int daylimit) {
        // 判断是否配置了日限，无日限则不控制
        if (daylimit <= 0) {
            return null;
        }
        String key = CacheKey.APK_TIME_MODEL + mark;

        Map<String, ChannelApkConfigTimeModel> result = (Map<String, ChannelApkConfigTimeModel>) redisClient.get(key);
        List<ChannelApkConfigTimeModel> rlist = null;
        if (result == null) {
            result = new HashMap<>();
            rlist = getChannelApkConfigTimeModelList(mark, ConstantsCmp.add);
            if (rlist != null && rlist.size() > 0) {
                for (ChannelApkConfigTimeModel t : rlist) {
                    t.setSpDayLimit((int) (t.getTimePercent() * daylimit / 100));
                    result.put(t.getTime(), t);
                }
                redisClient.put(key, result, 300);
            } else {
                List<TimeBaseModel> baseModelList = timeModelTempleteService.selectAllBaseModel();
                if (baseModelList != null) {
                    rlist = new ArrayList<ChannelApkConfigTimeModel>();
                    for (TimeBaseModel model : baseModelList) {
                        ChannelApkConfigTimeModel t = new ChannelApkConfigTimeModel();
                        t.setMark(mark);
                        t.setTime(model.getRateTime());
                        t.setCurrPercent(model.getCurrRate());
                        t.setTimePercent(model.getTotalRate());
                        t.setType(ConstantsCmp.add);
                        t.setSpDayLimit((int) (t.getTimePercent() * daylimit / 100));
                        result.put(t.getTime(), t);
                        rlist.add(t);
                    }
                    redisClient.put(key, result, 300);
                    channelApkLimitDAO.saveChannelApkConfigTimeModel(rlist);
                }
            }
        }
        return result;

    }

    @Override
    public List<ChannelApkConfigTimeModel> getChannelApkConfigTimeModelList(String mark, String type) {
        return channelApkLimitDAO.selectChannelApkConfigTimeModel(mark, type);
    }

    /**
     * getTimeModelByMark:获取当前mark的日限模型
     *
     * @param mark
     * @return
     * @author <a href="mailto:zhangbinghua@zhexinit.com" >zbh</a>
     */
    @Override
    public Map<String, ChannelApkConfigTimeModel> getTimeRetentModelByMark(String mark) {
        String key = CacheKey.APK_RETENT_TIME_MODEL + mark;
        Map<String, ChannelApkConfigTimeModel> result = (Map<String, ChannelApkConfigTimeModel>) redisClient.get(key);
        List<ChannelApkConfigTimeModel> rlist = null;
        if (result == null) {
            result = new HashMap<>();
            rlist = getChannelApkConfigTimeModelList(mark, ConstantsCmp.retent);
            if (rlist != null && rlist.size() > 0) {
                for (ChannelApkConfigTimeModel t : rlist) {
                    result.put(t.getTime(), t);
                }
                redisClient.put(key, result, 300);
            } else {
                List<TimeBaseModel> baseModelList = timeModelTempleteService.selectAllBaseModel();
                if (baseModelList != null) {
                    rlist = new ArrayList<ChannelApkConfigTimeModel>();
                    for (TimeBaseModel model : baseModelList) {
                        ChannelApkConfigTimeModel t = new ChannelApkConfigTimeModel();
                        t.setMark(mark);
                        t.setTime(model.getRateTime());
                        t.setCurrPercent(model.getCurrRate());
                        t.setTimePercent(model.getTotalRate());
                        t.setType(ConstantsCmp.retent);
                        result.put(t.getTime(), t);
                        rlist.add(t);
                    }
                    redisClient.put(key, result, 300);
                    channelApkLimitDAO.saveChannelApkConfigTimeModel(rlist);
                }
            }
        }
        return result;
    }

    @Override
    public int getTimeLimit(String apk, int dayLimit) {
        try {
            Map<String, ChannelApkConfigTimeModel> map = getTimeModelByMark(apk, dayLimit);
            Calendar rightNow = Calendar.getInstance();
            rightNow.setTimeZone(TimeZone.getDefault());
            String current = DateFormatUtils.format(rightNow.getTime(), "yyyyMMdd HH");
            int mm = Integer.parseInt(DateFormatUtils.format(rightNow.getTime(), "mm"));
            int nowmm = mm;
            if (mm < 15) {
                current = current + ":00:00";
            } else {
                mm = (mm / 15) * 15;
                current = current + ":" + mm + ":00";
            }
            String first = current.substring(9);
            ChannelApkConfigTimeModel firsetModel = map.get(first);
            double firsetNum = firsetModel.getSpDayLimit();
            if (first.equals("00:00:00")) {
                return (int) (firsetNum * (nowmm % 15 / 15d));
            } else if (first.equals("23:45:00")) {
                return dayLimit;
            } else {
                rightNow.setTimeInMillis(new SimpleDateFormat("yyyyMMdd HH:mm:ss").parse(current).getTime() + 900000);
                String nextDate = DateFormatUtils.format(rightNow.getTime(), "yyyyMMdd HH:mm:ss");// 下一个15分钟
                String second = nextDate.substring(9);
                ChannelApkConfigTimeModel secondModel = map.get(second);
                double secodeNum = secondModel.getSpDayLimit();
                return (int) (firsetNum + ((secodeNum - firsetNum) * (nowmm % 15 / 15d)));
            }
        } catch (Exception e) {
            LOGGER.info("mark [{}]的日限正太模型没有配置", apk);
        }
        return 0;
    }

    /**
     * 获取当前的间隔时间
     *
     * @return
     */
    private String getCurrentIntervalTime() {
        Calendar rightNow = Calendar.getInstance();
        SimpleDateFormat sdfMM = new SimpleDateFormat("mm");
        SimpleDateFormat sdf = new SimpleDateFormat("HH");
        String current = sdf.format(rightNow.getTime());
        int mm = Integer.parseInt(sdfMM.format(rightNow.getTime()));
        if (mm < 15) {
            current = current + ":00:00";
        } else {
            mm = (mm / 15) * 15;
            current = current + ":" + mm + ":00";
        }

        return current;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.jsbd.boss.service.IChannelLimitService#saveLimitModelBymark(org.jsbd
     * .boss.domian.ChannelApkConfigTimeModel)
     */
    @Override
    public void saveLimitModelBymark(ChannelApkConfigTimeModel model) {
        ChannelApkConfig config = new ChannelApkConfig();
        String mark = model.getMark();
        config.setMark(mark);
        List<ChannelApkConfig> list = channelApkConfigDAO.selectApkInfos(config);
        if (list != null && list.size() > 0) {
            ChannelApkConfig apkConfig = list.get(0);
            Integer newLimit = apkConfig.getIsNewUserLimit();
            if (newLimit != null && newLimit == 1) {
                Integer dayLimit = apkConfig.getDaylimit();
                model.setSpDayLimit((int) (dayLimit * model.getTimePercent() / 100));
            }
        }
        channelApkLimitDAO.saveChannelApkConfigTimeModel(model);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.jsbd.boss.service.IChannelLimitService#getCurrentAddLimitModel(java
     * .lang.String, int)
     */
    @Override
    public ChannelApkConfigTimeModel getCurrentAddLimitModel(String mark, int dayLimit) {
        // 如果有配置分时间则去当前时间的现在数量，如果没有配置分时间则取总数
        String current = getCurrentIntervalTime();
        // 判断是否配置了日限，无日限则不控制
        if (dayLimit <= 0) {
            return null;
        }
        Map<String, ChannelApkConfigTimeModel> timeModelMap = getTimeModelByMark(mark, dayLimit);
        // 如果没有mark的模型，证明没有配置日限
        if (timeModelMap == null) {
            LOGGER.info("mark没有取到日限模型，mark[{}]", mark);
            return null;
        }
        ChannelApkConfigTimeModel timeModel = timeModelMap.get(current);
        return timeModel;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.jsbd.boss.service.IChannelLimitService#saveLimitModelList(java.util
     * .List)
     */
    @Override
    public void saveLimitModelList(List<ChannelApkConfigTimeModel> list, int type) {
        if (type == 0) {
            int dayLimit = 0;
            if (list != null && list.size() > 0) {
                ChannelApkConfigTimeModel model = list.get(0);
                String mark = model.getMark();
                if (mark.length() < 8) {
                    BrushConfig brushConfig = new BrushConfig();
                    brushConfig.setId(Integer.parseInt(mark));
                    BrushConfig brushConfig1 = brushConfigDao.selectConfig(brushConfig);
                    dayLimit = brushConfig1.getDayLimit();
                } else {
                    ChannelApkConfig config = new ApkRetentConfig();
                    config.setMark(mark);
                    List<ChannelApkConfig> markList = channelApkConfigDAO.selectApkInfos(config);
                    dayLimit = markList.get(0).getDaylimit();
                }
                for (ChannelApkConfigTimeModel configModel : list) {
                    configModel.setSpDayLimit((int) (dayLimit * configModel.getTimePercent() / 100));
                    configModel.setType("0");
                }
            }
        } else {
            for (ChannelApkConfigTimeModel configModel : list) {
                configModel.setType("1");
            }
        }
        channelApkLimitDAO.saveChannelApkConfigTimeModel(list);
    }

}
